// import com.alibaba.druid.DbType*;
// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.ast.SQLCommentHint*;
// import com.alibaba.druid.sql.ast.SQLExpr*;
// import com.alibaba.druid.sql.ast.SQLName*;
// import com.alibaba.druid.sql.ast.SQLStatementImpl;
// import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
// import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
// import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor*;

// import java.io.IOException;
// import java.util.ArrayList;
// import java.util.std::list;

#include "../../../sql/ast/statement/SQLSetStatement.h"
#include "../../../sql/ast/SQLCommentHint.h"
#include "../../../sql/ast/SQLExpr.h"
#include "../../../sql/ast/SQLName.h"
#include "../../../sql/ast/SQLStatementImpl.h"
#include "../../../sql/ast/expr/SQLBinaryOpExpr.h"
#include "../../../sql/ast/expr/SQLBinaryOperator.h"
#include "../../../sql/ast/expr/SQLIntegerExpr.h"
#include "../../../sql/visitor/SQLASTVisitor.h"
#include "../../../Exception/FastsqlException.h"
#include "../../../utils/listTran.h"
#include "SQLAssignItem.h"

SQLSetStatement_Option_ptr SQLSetStatement_Option::IDENTITY_INSERT = SQLSetStatement_Option_ptr(new SQLSetStatement_Option(1ULL << 0, make_string_ptr("IDENTITY INSERT")));
SQLSetStatement_Option_ptr SQLSetStatement_Option::PASSWORD = SQLSetStatement_Option_ptr(new SQLSetStatement_Option(1ULL << 1, make_string_ptr("PASSWORD"))); // mysql
SQLSetStatement_Option_ptr SQLSetStatement_Option::GLOBAL = SQLSetStatement_Option_ptr(new SQLSetStatement_Option(1ULL << 2, make_string_ptr("GLOBAL")));
SQLSetStatement_Option_ptr SQLSetStatement_Option::SESSION = SQLSetStatement_Option_ptr(new SQLSetStatement_Option(1ULL << 3, make_string_ptr("SESSION")));
SQLSetStatement_Option_ptr SQLSetStatement_Option::LOCAL = SQLSetStatement_Option_ptr(new SQLSetStatement_Option(1ULL << 4, make_string_ptr("LOCAL")));
SQLSetStatement_Option_ptr SQLSetStatement_Option::PROJECT = SQLSetStatement_Option_ptr(new SQLSetStatement_Option(1ULL << 5, make_string_ptr("PROJECT")));

SQLSetStatement_Option::SQLSetStatement_Option(uint64_t mask, string_ptr name)
{
  this->name = name;
  this->mask = mask;
}

SQLSetStatement::SQLSetStatement()
{
  items = std::make_shared<std::list<SQLAssignItem_ptr>>();
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
}

SQLSetStatement::SQLSetStatement(DbType_ptr dbType)
    : SQLStatementImpl(dbType)
{
  items = std::make_shared<std::list<SQLAssignItem_ptr>>();
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
}

SQLSetStatement::SQLSetStatement(SQLExpr_ptr target, SQLExpr_ptr value)
    : SQLSetStatement(target, value, nullptr)
{
}

SQLSetStatement::SQLSetStatement(SQLExpr_ptr target, SQLExpr_ptr value, DbType_ptr dbType)
    : SQLStatementImpl(dbType)
{
  items = std::make_shared<std::list<SQLAssignItem_ptr>>();
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  SQLAssignItem_ptr item = SQLAssignItem_ptr(new SQLAssignItem(target, value));
  item->setParent(SharedObject(SQLSetStatement));
  this->items->push_back(item);
}

SQLSetStatement *SQLSetStatement::plus(SQLName_ptr target)
{
  SQLExpr_ptr value =
      SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(
          std::dynamic_pointer_cast<SQLName>(target->clone()),
          SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Add)),
          SQLIntegerExpr_ptr(new SQLIntegerExpr(1))));
  return new SQLSetStatement(target, value);
}

SQLAssignItem_list_ptr SQLSetStatement::getItems()
{
  return items;
}

void SQLSetStatement::setItems(SQLAssignItem_list_ptr items)
{
  this->items = items;
}

SQLCommentHint_list_ptr SQLSetStatement::getHints()
{
  return hints;
}

void SQLSetStatement::setHints(SQLCommentHint_list_ptr hints)
{
  this->hints = hints;
}

std::shared_ptr<SQLSetStatement_Option> SQLSetStatement::getOption()
{
  return option;
}

void SQLSetStatement::setOption(std::shared_ptr<SQLSetStatement_Option> option)
{
  this->option = option;
}

void SQLSetStatement::set(SQLExpr_ptr target, SQLExpr_ptr value)
{
  SQLAssignItem_ptr assignItem = SQLAssignItem_ptr(new SQLAssignItem(target, value));
  assignItem->setParent(SharedObject(SQLSetStatement));
  this->items->push_back(assignItem);
}

//@Override
void SQLSetStatement::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLSetStatement)))
  {
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLAssignItem, SQLObject>(this->items);
    acceptChild(visitor, tmp1);
    SQLObject_list_ptr tmp2 = ListTran::tran_class<SQLCommentHint, SQLObject>(this->hints);
    acceptChild(visitor, tmp2);
  }
  visitor->endVisit(SharedObject(SQLSetStatement));
}

void SQLSetStatement::output(std::stringstream * buf)
{
  try
  {
    (*buf)<<"SET ";

    auto it_items = items->begin();
    for (int i = 0; i < items->size(); ++i)
    {
      if (i != 0)
      {
        (*buf)<<", ";
      }

      std::advance(it_items, i);
      SQLAssignItem_ptr item = *it_items;
      item->output(buf);
    }
  }
  // catch (IOException ex)
  catch (...)
  {
    // throw new FastsqlException("output error", ex);
    throw new FastsqlException(make_string_ptr("output error"));
  }
}

SQLObject_ptr SQLSetStatement::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLSetStatement>(new SQLSetStatement());
  std::shared_ptr<SQLSetStatement> x = std::dynamic_pointer_cast<SQLSetStatement>(clone_tmp);
  // SQLSetStatement *x = new SQLSetStatement();
  for (SQLAssignItem_ptr item : *items)
  {
    SQLAssignItem_ptr item2 = std::dynamic_pointer_cast<SQLAssignItem>(item->clone());
    item2->setParent(x);
    x->items->push_back(item2);
  }
  if (hints != nullptr)
  {
    for (SQLCommentHint_ptr hint : *hints)
    {
      SQLCommentHint_ptr h2 = std::dynamic_pointer_cast<SQLCommentHint>(hint->clone());
      h2->SQLObjectImpl::setParent(x);
      x->hints->push_back(h2);
    }
  }
  return x;
}

SQLAssignItem_list_ptr SQLSetStatement::getChildren()
{
  return this->items;
}
